﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using Newtonsoft.Json;
using BCCommon;
using BCCommon.Enums;
using BCCommon.Extensions;
using BCCommon.FreightEnums;
using BCCommon.PaymentEnums;
using BCService.Common.Payment.Payment.WeixinPay;
using Microsoft.Extensions.Configuration;

namespace BCService.Common.Payment.Payment
{
    public class WeixinPayHelper : IWeixinPayHelper
    {
        private const string URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        private readonly IConfiguration _configuration;
        private readonly IWeiXinPayPlugConfig _wxConfig;
        private readonly IWeiXinPayPlug _wxPlug;
        public WeixinPayHelper(IConfiguration configuration)
        {
            _configuration = configuration;
            _wxConfig = new WeiXinPayPlugConfig(configuration);
            _wxPlug = new WeiXinPayPlug(_configuration, _wxConfig);
        }

        public IWeiXinPayPlug GetWeiXinPayPlug()
        {
            return _wxPlug;
        }

        /// <summary>
        /// 调起支付
        /// </summary>
        /// <param name="appType">应用类型</param>
        /// <param name="osType">系统类型</param>
        /// <param name="payChannelType">支付渠道</param>
        /// <param name="userId">用户Id</param>
        /// <param name="paymentRecordId">支付记录Id</param>
        /// <param name="subject">交易订单标题</param>
        /// <param name="newAmount">金额</param>
        /// <param name="orderType">订单类型</param>
        /// <param name="referenceNumber">相关业务编号</param>
        /// <param name="tradeType">交易类型</param>
        /// <param name="createIP">来源Ip</param>
        /// <returns></returns>
        public SortedDictionary<string, object> CreateTryPay( SourceAppType appType, SourceOSType osType, PaymentChannelType payChannelType, long userId, long paymentRecordId,string subject, decimal newAmount, FlowType orderType, string referenceNumber, string tradeType, string createIP)
        {
            //获取指定端的配置信息
            _wxConfig.InitConfig(appType);

            //预支付
            var result = UnifiedOrder(payChannelType, userId, paymentRecordId, subject, newAmount, orderType, referenceNumber, tradeType, createIP, _wxConfig);
            _wxPlug.ClearAllValue();

            //APP调起支付参数构造
            _wxPlug.SetValue("appid", _wxConfig.APP_ID);                //微信应用Id
            _wxPlug.SetValue("partnerid", _wxConfig.MCH_ID);            //商户号
            _wxPlug.SetValue("prepayid", result["prepay_id"]);         //
            _wxPlug.SetValue("package", "Sign=WXPay");
            _wxPlug.SetValue("noncestr", Guid.NewGuid().ToString("N"));
            _wxPlug.SetValue("timestamp", _wxPlug.GenerateTimeStamp());
            _wxPlug.SetValue("sign", _wxPlug.MakeSign());

            return _wxPlug.GetDictionary();
        }

        /// <summary>
        /// 获取支付二维码
        /// </summary>
        /// <param name="appType">APP类型</param>
        /// <param name="osType">环境操作系统</param>
        /// <param name="payChannelType">支付渠道类型</param>
        /// <param name="userId">用户Id</param>
        /// <param name="paymentRecordId">支付记录Id</param>
        /// <param name="subject">支付订单标题</param>
        /// <param name="newAmount">金额</param>
        /// <param name="orderType">支付业务类型</param>
        /// <param name="referenceNumber">订单号</param>
        /// <param name="tradeType">交易方式</param>
        /// <param name="createIP">请求Ip</param>
        /// <returns></returns>
        public SortedDictionary<string, object> CreatQRCode(SourceAppType appType, SourceOSType osType, PaymentChannelType payChannelType, long userId, long paymentRecordId,string subject, decimal newAmount, FlowType orderType, string referenceNumber, string tradeType, string createIP)
        {
            _wxConfig.InitConfig(appType);
            //预支付
            return UnifiedOrder(payChannelType, userId, paymentRecordId, subject, newAmount, orderType, referenceNumber, tradeType, createIP, _wxConfig);
        }

        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="payChannelType">支付渠道类型</param>
        /// <param name="userId">用户Id</param>
        /// <param name="appType">APP类型</param>
        /// <param name="osType">环境操作系统</param>
        /// <param name="trade_no">订单号</param>
        /// <param name="outTradeNo">退款订单号</param>
        /// <param name="refundAmount">退款金额</param>
        /// <param name="amount">总订单金额</param>
        /// <returns></returns>
        public SortedDictionary<string, object> Refund(PaymentChannelType payChannelType, long userId, SourceAppType appType, SourceOSType osType, long trade_no, string outTradeNo, decimal refundAmount, decimal amount)
        {
            _wxConfig.InitConfig(appType);
            //APP调起支付参数构造
            _wxPlug.SetValue("appid", _wxConfig.APP_ID);
            _wxPlug.SetValue("mch_id", _wxConfig.MCH_ID);            //商户号
            _wxPlug.SetValue("nonce_str", Guid.NewGuid().ToString("N"));
            _wxPlug.SetValue("out_trade_no", trade_no.ToString("0000000000"));
            _wxPlug.SetValue("out_refund_no", outTradeNo);
            _wxPlug.SetValue("total_fee", (amount * 100).ToString("f0"));
            _wxPlug.SetValue("refund_fee", (refundAmount * 100).ToString("f0"));
            _wxPlug.SetValue("notify_url", string.Format(_configuration["PayNotify:postUrl"], payChannelType, trade_no));
            _wxPlug.SetValue("sign", _wxPlug.MakeSign());
            string URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            return _wxPlug.PostRequest(URL, true);
        }

        /// <summary>
        /// 企业付款（提现）
        /// </summary>
        /// <param name="appType">系统类型</param>
        /// <param name="trade_no">订单编号</param>
        /// <param name="openId">开放Id</param>
        /// <param name="amount">金额</param>
        /// <param name="createIP">访问IP</param>
        /// <returns></returns>
        public SortedDictionary<string, object> Transfers(SourceAppType appType, long trade_no, string openId, decimal amount, string createIP)
        {
            _wxConfig.InitConfig(appType);

            //APP调起支付参数构造
            _wxPlug.SetValue("mch_appid", _wxConfig.APP_ID);
            _wxPlug.SetValue("mchid", _wxConfig.MCH_ID);            //商户号
            _wxPlug.SetValue("nonce_str", Guid.NewGuid().ToString("N"));
            _wxPlug.SetValue("partner_trade_no", trade_no.ToString("0000000000"));
            _wxPlug.SetValue("openid", openId);
            _wxPlug.SetValue("check_name", "NO_CHECK");//NO_CHECK：不校验真实姓名 FORCE_CHECK：强校验真实姓名
            _wxPlug.SetValue("amount", (amount * 100).ToString("f0"));
            _wxPlug.SetValue("desc", $"{trade_no}--提现");
            _wxPlug.SetValue("spbill_create_ip", createIP);
            _wxPlug.SetValue("sign", _wxPlug.MakeSign());
            string URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
            return _wxPlug.PostRequest(URL, true);
        }

        /// <summary>
        /// 获取访问Token
        /// </summary>
        /// <param name="appType">App类型</param>
        /// <param name="code">code码</param>
        /// <returns></returns>
        private SortedDictionary<string, object> GetAccessToken(SourceAppType appType, string code)
        {
            string url = "https://api.weixin.qq.com/sns/oauth2/access_token";
            _wxConfig.InitConfig(appType);
            _wxPlug.SetValue("appid", _wxConfig.APP_ID);
            _wxPlug.SetValue("secret", _wxConfig.APP_SECRET);
            _wxPlug.SetValue("code", code);
            _wxPlug.SetValue("grant_type", "authorization_code");
            var data = _wxPlug.GetRequest(url);
            if (data.TryGetValue("access_token", out object parameter))
            {
                return data;
            }
            else
            {
                throw new ArgumentException(data.GetValueOrDefault("errmsg").ToString());
            }
        }

        /// <summary>
        /// 获取授权信息
        /// </summary>
        /// <param name="appType">App类型</param>
        /// <param name="code">code码</param>
        /// <returns></returns>
        public string GetAuthInfo(SourceAppType appType, string code)
        {
            var dic = GetAccessToken(appType, code);
            string url = "https://api.weixin.qq.com/sns/userinfo";
            _wxConfig.InitConfig(appType);
            _wxPlug.SetValue("access_token", dic.GetValueOrDefault("access_token"));
            _wxPlug.SetValue("openid", dic.GetValueOrDefault("openid"));
            var data = _wxPlug.GetRequest(url);
            if (data.TryGetValue("openid", out object parameter))
            {
                return JsonConvert.SerializeObject(data);
            }
            else
            {
                throw new ArgumentException("授权获授权用户信息过程出现异常");
            }
        }

        /// <summary>
        /// 订单查询
        /// </summary>
        /// <param name="appType">APP类型</param>
        /// <param name="out_trade_no">商户系统内部的订单号</param>
        /// <returns></returns>
        public SortedDictionary<string, object> OrderQuery(SourceAppType appType, long out_trade_no)
        {
            _wxConfig.InitConfig(appType);
            //APP调起支付参数构造
            _wxPlug.SetValue("appid", _wxConfig.APP_ID);             //APPid
            _wxPlug.SetValue("mch_id", _wxConfig.MCH_ID);            //商户号
            _wxPlug.SetValue("out_trade_no", out_trade_no.ToString("0000000000"));     //支付订单号(对应支付记录Id)
            _wxPlug.SetValue("nonce_str", Guid.NewGuid().ToString("N"));
            _wxPlug.SetValue("sign", _wxPlug.MakeSign());
            string URL = "https://api.mch.weixin.qq.com/pay/orderquery";
            return _wxPlug.PostRequest(URL);
        }

        /// <summary>
        /// 统一下单
        /// </summary>
        /// <param name="payChannelType">支付渠道</param>
        /// <param name="userId">用户ID</param>
        /// <param name="paymentRecordId">记录ID</param>
        /// <param name="subject">交易订单标题</param>
        /// <param name="newAmount">支付金额（单位：元）</param>
        /// <param name="orderType">支付订单的类型</param>
        /// <param name="referenceNumber">标题</param>
        /// <param name="tradeType">交易类型</param>
        /// <param name="createIP">创建IP</param>
        /// <param name="wxConfig">微信支付组件配置</param>
        /// <returns></returns>
        private SortedDictionary<string, object> UnifiedOrder(PaymentChannelType payChannelType, long userId, long paymentRecordId,string subject, decimal newAmount, FlowType orderType, string referenceNumber, string tradeType, string createIP, IWeiXinPayPlugConfig wxConfig)
        {
            //预支付构造传递参数
            _wxPlug.SetValue("appid", wxConfig.APP_ID);    //AppId
            _wxPlug.SetValue("mch_id", wxConfig.MCH_ID); //商户号
            _wxPlug.SetValue("spbill_create_ip", createIP); //请求的IP
            _wxPlug.SetValue("nonce_str", Guid.NewGuid().ToString("N")); //随机字符串
            _wxPlug.SetValue("body", subject);
            _wxPlug.SetValue("out_trade_no", paymentRecordId.ToString("0000000000"));
            _wxPlug.SetValue("total_fee", (newAmount * 100).ToString("f0")); //支付金额单位为分 乘以100 支付不接受小数点/千分号等
            _wxPlug.SetValue("notify_url", string.Format(_configuration["PayNotify:postUrl"], payChannelType, paymentRecordId));
            _wxPlug.SetValue("trade_type", tradeType);
            _wxPlug.SetValue("sign", _wxPlug.MakeSign()); //签名

            //预支付请求
            return _wxPlug.PostRequest(URL,true);
        }
    }

    
    
}